/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controler;

import gui.MyButton;
import gui.OpenButton;
import gui.RulesPopUpMenu;
import gui.SudokuBoardGUI;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.event.WindowListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import rules.Rule;
import sudoku.RuleBasedSudokuSolver;
import types.ColoringInfo;
import types.Field;
import types.ISudokuMatrix;

import utils.FieldAppRules;
import utils.GuiHelper;
import utils.SudokuMatrixIO;

/**
 *
 * @author Creator
 */
public class SudokuControler implements ActionListener, MouseListener, WindowListener{

    private SudokuBoardGUI sGui = null;
    private String filename = "./board.txt";
    private int boardSize = 9;
    private ISudokuMatrix matrix = null;
    private String separator = "";
    Collection allRules;
    RuleBasedSudokuSolver rulBaseSdkSolver;
    RulesPopUpMenu rlPupUpGui = null;
    Field markedField = new Field();
    boolean changeField = false;
    private FieldAppRules fileAppRules = null;
    

    public SudokuControler(){
        separator = System.getProperty( "file.separator" );
        sGui = new SudokuBoardGUI(boardSize);
        sGui.getJFrame().setVisible(true);
        sGui.getJFrame().addWindowListener(this);
        initButtonsActionListener();
        initTextFieldMousListener();
        rlPupUpGui = new RulesPopUpMenu();
        readConfigSudoku(filename);
        //readConfigSudoku(sGui.getSelectedFile());
        fillSudokuBaord(matrix);   
    }
    public void initTextFieldMousListener(){
        Collection f = null;
        int block = 0;
        int field = 0;
        for( block=0; block<boardSize; block++){
            for (field=0; field<boardSize; field++){

                     sGui.setMouseListener(block, field, this);
                }
            }
    }
    /**
     * Set ActionListener for all button
     */
    public void initButtonsActionListener(){
        int size = sGui.getButtons().length;
        for (int i=0; i<size; i++){
            JButton button = (JButton)sGui.getButtons()[i];
            button.addActionListener(this);
        }
         sGui.downBotton().addActionListener(this);
         sGui.upBotton().addActionListener(this);
          //sGui.downBotton().setVisible(true);

    }
    public void readConfigSudoku(String filename){
        try {
            matrix = SudokuMatrixIO.getSudokuMatrix(filename);
            rulBaseSdkSolver = new RuleBasedSudokuSolver(matrix);
            sGui.reset();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(SudokuControler.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
    public void fillSudokuBaord(ISudokuMatrix matrix){
         Collection f = null;
         Iterator itr = null;
         int block = 0;
         int field = 0;
        for( block=0; block<boardSize; block++){
            try {
                f = matrix.getQuadratDigits(block + 1);
                itr = f.iterator();
            } catch (Exception ex) {
                Logger.getLogger(SudokuControler.class.getName()).log(Level.SEVERE, null, ex);
            }
             
            for (field=0; field<boardSize; field++){
                if (itr.hasNext()){
                 Integer a = (Integer) itr.next();
                 int x = GuiHelper.calculateX(block, field);
                 int y = GuiHelper.calculateY(block, field);
                 Collection cl = rulBaseSdkSolver.getMatrixApplicableRules(x, y);
                 if (a > 0){
                     sGui.setFild(block, field, a, Color.WHITE);
                 }else if ( !cl.isEmpty()){
                     GuiHelper.sortColOfRulesByWeight(cl);
                     Iterator rulsItr = cl.iterator();
                     if (rulsItr.hasNext()){
                         Rule rule = (Rule)rulsItr.next();
                        sGui.setFild(block, field, getWeightColor(rule.getWeight(rule.getQuadrat()),
                                GuiHelper.getMinApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()),
                                GuiHelper.getMaxApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules())));
                     }
                     
                 }else if ( cl.isEmpty()){
                     sGui.setFild(block, field, Color.GRAY);
                     
                 }
                }
            }
        }
    }
    /**
     *
     * The function generate color for field by means of current weight
     * and max, min of weight
     * @param weight
     * @param min
     * @param max
     * @return color of weight
     */
    public static Color getWeightColor(int weight, int min, int max){

        float maxColor = 0.3f;
        float norMax = ((float)max)/100;
        float ratio  = (maxColor/norMax);
        float color = 0.0f;

        // if weight equals min then return green color
        if (weight == min){
             color = maxColor;
             return Color.getHSBColor(color, 1.0f, 1.0f);
        // if weight equals max then return red color
        }else if (weight == max){
            color = 0.0f;
            return Color.getHSBColor(color, 1.0f, 1.0f);
        // else calculate color
        }else{
            float  w = weight;
            color = maxColor - (w/100 * ratio);
            return Color.getHSBColor(color, 1.0f, 1.0f);
        }   
    }
    public void saveGame(){
        try {
                filename = sGui.getSavePhat(filename);
                if (separator.equals("\\")) {
                    filename = SudokuMatrixIO.replaceToWinSeparator(filename);
                }
                if (!filename.equals("")){
                    SudokuMatrixIO.saveSudokuMatrix(filename, matrix);
                }

            } catch (FileNotFoundException ex) {
                Logger.getLogger(SudokuControler.class.getName()).log(Level.SEVERE, null, ex);
            }catch (IOException ex) {
                Logger.getLogger(SudokuControler.class.getName()).log(Level.SEVERE, null, ex);
            }
    }
    
    /**
     * Perofmed action on klicked a button
     * @param e
     */
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Load a File")){
           if (separator.equals("\\")){
             filename =  SudokuMatrixIO.replaceToUnixSeparator(sGui.getSelectedFile());
           }else{
             filename = sGui.getSelectedFile();
           }
           if ( !filename.equals("")){
             readConfigSudoku(filename);
             fillSudokuBaord(matrix);
           }
        }else if (e.getActionCommand().equals("Close")){
          if (changeField){
            int option = sGui.getSaveDialog();
            if ( option == JOptionPane.YES_OPTION ){
                saveGame();
            } else if ( option == JOptionPane.NO_OPTION ){
                    sGui.getJFrame().setVisible(false);
                    sGui.getJFrame().dispose();
                    System.exit(0);
                }else if ( option == JOptionPane.CANCEL_OPTION ){
                     System.out.println( "Keine Antwort" );
                }
                else if ( option == JOptionPane.CLOSED_OPTION )
                System.out.println( "so was, abgebrochen..." );
            }else{
              System.exit(0);
            }
        }else if (e.getActionCommand().equals("Save a File")){
            saveGame();
        }else if (e.getSource() instanceof MyButton){
            int result = rulBaseSdkSolver.getSolutionForField(markedField.x, markedField.y);
            matrix.insertElementAt(result,markedField.x, markedField.y);
            rulBaseSdkSolver.setConf(matrix);
            this.fillSudokuBaord(matrix);
            changeField = true;
            sGui.clearRulesList();

            if (sGui.downBotton().isVisible()){
                sGui.downBotton().setVisible(false);
            }
            if (sGui.upBotton().isVisible()){
                sGui.upBotton().setVisible(false);
            }



        }else if (e.getActionCommand().equals("up")){
            System.out.println("UP");
            if (fileAppRules.hasPrevious()){

                  sGui.showRules(this, fileAppRules.previous(), GuiHelper.getMinApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()),
                  GuiHelper.getMaxApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()));

                  if(fileAppRules.hasNext()){
                      sGui.downBotton().setVisible(true);

                  }else{
                      sGui.downBotton().setVisible(false);

                  }
                  
                  if(fileAppRules.hasPrevious()){
                      sGui.upBotton().setVisible(true);

                  }else{
                      sGui.upBotton().setVisible(false);

                  }
                   
                   sGui.getJRulePane().updateUI();
            }
        }else if (e.getActionCommand().equals("down")){
            System.out.println("DOWN");
            if (fileAppRules.hasNext()){
                  sGui.showRules(this, fileAppRules.next(), GuiHelper.getMinApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()),
                  GuiHelper.getMaxApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()));

                
                  if(fileAppRules.hasNext()){
                      sGui.downBotton().setVisible(true);
                     
                  }else{
                      sGui.downBotton().setVisible(false);
   
                  }
                  
                  if(fileAppRules.hasPrevious()){
                      sGui.upBotton().setVisible(true);

                  }else{
                      sGui.upBotton().setVisible(false);

                  }
                   sGui.getJRulePane().updateUI();
            }
        }
    }
   public void mouseReleased(MouseEvent event)
   {
       if (event.getComponent() instanceof JButton) {

            return;
	}
        JTextField tf = (JTextField)event.getComponent();
        String bf[] = tf.getName().split(";");
        markedField.quatrat        = Integer.valueOf(bf[0]);
        markedField.fieldInQuadrat = Integer.valueOf(bf[1]);

        if (tf.getText().equals("")){
            System.out.println("Block: "+markedField.quatrat+" Feld: "+markedField.fieldInQuadrat);
            markedField.x = GuiHelper.calculateX(markedField.quatrat, markedField.fieldInQuadrat);
            markedField.y = GuiHelper.calculateY(markedField.quatrat, markedField.fieldInQuadrat);
            this.fileAppRules = new FieldAppRules(rulBaseSdkSolver.getMatrixApplicableRules(markedField.x, markedField.y));

             sGui.upBotton().setVisible(false);
             sGui.downBotton().setVisible(false);

            if (fileAppRules.getRuleSize() > fileAppRules.getShowRulesSize()){
                sGui.downBotton().setVisible(true);
                sGui.getJRulePane().updateUI();
            }

            System.out.println("Rule Size: " +fileAppRules.getRuleSize());

            sGui.showRules(this, fileAppRules.getAktRules(), GuiHelper.getMinApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()),
                            GuiHelper.getMaxApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()));
            // sGui.showRules(event, this, rulBaseSdkSolver.getMatrixApplicableRules(markedField.x, markedField.y), GuiHelper.getMinApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()),
             //               GuiHelper.getMaxApplicableRulesOfWholeBoard(rulBaseSdkSolver.getWholeMatrixApplicableRules()));
            //rlPupUpGui.createPopupMenu(event, this, rulBaseSdkSolver.getMatrixApplicableRules(markedField.x, markedField.y));
        }
   }
    public void mouseClicked(MouseEvent e) {}
    
    //right click in linux prduces this event (mouse pressed event!
    public void mousePressed(MouseEvent e) {
        this.mouseReleased(e);
    }
    public void mouseEntered(MouseEvent e) {
    	if (e.getComponent() instanceof JButton) {
    		JButton ruleButton = (JButton) e.getComponent();
        	String ruleName = ruleButton.getActionCommand();
        	
        	Vector<Rule> currentRules = (Vector<Rule>) fileAppRules.getAllRules();
        	for (Rule rule : currentRules) {
    			if(rule.getName().equalsIgnoreCase(ruleName)) {
    				if (rule.isApplicable(markedField.x, markedField.y, matrix)) {
    					ColoringInfo colorInfo = rule.getCheckedUnits(markedField.x, markedField.y, matrix);
    					
    					//CLEAR BOARD (WHITE COLOR)
    					for (int block = 0; block < boardSize; block++) {
    						for (int field = 0; field < boardSize; field++) {
    							sGui.setFild(block, field, Color.WHITE);
    						}
    					}
    					
    					for (int block = 1; block <= boardSize; block++) {
							for (int field = 1; field <= boardSize; field++) {
								if (colorInfo.getBlocks().contains(block)) {
									sGui.setFild(block-1, field-1, ruleButton.getBackground());
								}
								else if (colorInfo.getRows().contains(GuiHelper.calculateX(block-1, field-1))) {
									sGui.setFild(block-1, field-1, ruleButton.getBackground());
								}
								else if (colorInfo.getColums().contains(GuiHelper.calculateY(block-1, field-1))) {
									sGui.setFild(block-1, field-1, ruleButton.getBackground());
								}
							}
						}
    					sGui.setFild(markedField.quatrat, markedField.fieldInQuadrat, Color.GRAY);
    				}
    			}
    		}
    	}
    }
    public void mouseExited(MouseEvent e) {
        if (e.getComponent() instanceof JButton){
            System.out.println("Hallo MouseExited");
            fillSudokuBaord(matrix);
        }
    	
    }
    public static void main(String[] argv){

         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal's use of bold fonts
               // UIManager.put("swing.boldMetal", Boolean.FALSE);
                 SudokuControler sc = new SudokuControler();
            }
        });
    }

    public void windowOpened(WindowEvent e) {
       // throw new UnsupportedOperationException("Not supported yet.");
    }

    public void windowClosing(WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
        if (changeField){
            int option = sGui.getSaveDialog();
            if ( option == JOptionPane.YES_OPTION ){
                saveGame();
            } else if ( option == JOptionPane.NO_OPTION ){
                    sGui.getJFrame().setVisible(false);
                    sGui.getJFrame().dispose();
                    System.exit(0);
                }else if ( option == JOptionPane.CANCEL_OPTION ){
                     System.out.println( "Keine Antwort" );
                }
                else if ( option == JOptionPane.CLOSED_OPTION )
                System.out.println( "so was, abgebrochen..." );
            }else{
              System.exit(0);
            }
       
    }

    public void windowClosed(WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");

        
    }

    public void windowIconified(WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void windowDeiconified(WindowEvent e) {
       // throw new UnsupportedOperationException("Not supported yet.");
    }

    public void windowActivated(WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void windowDeactivated(WindowEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

   
        
}
